functor
export
   AplicarMovimientos
   CalcularMovimientos
   PartirTren
	MoverVagones
import
   Lista
	System
define
   % Devuelve la lista de los estados que resulta de aplicar los movimientos Ms
   % a partir del estado inicial E.
   fun {AplicarMovimientos E Ms}
		case Ms of nil then [E]
		[] M|Mr then 
			E|{AplicarMovimientos {AplicarMovimiento E M} Mr}
		end				
   end

	fun {AplicarMovimiento E M}
		case M of uno(N) then
			Ec = {MoverVagones E.principal E.uno N}
			in
			estado(principal:Ec.1 uno:Ec.2 dos:E.dos)
		[] dos(N) then
			Ec = {MoverVagones E.principal E.dos N}
			in
			estado(principal:Ec.1 uno:E.uno dos:Ec.2)
		end      
	end

	fun {MoverVagones Ps Vs N}
		if N < 0 then
		{Lista.agregar Ps {Lista.tomar Vs ~N}}#{Lista.eliminar Vs ~N}
		elseif N > 0 then L = {Lista.longitud Ps} - N in
		{Lista.tomar Ps L}#{Lista.agregar {Lista.eliminar Ps L} Vs}
		else Ps#Vs
		end
	end

   % Devuelve la lista de movimientos necesarios para transformar el estado
   % estado(principal:Xs uno:nil dos:nil) en 
   % estado(principal:Ys uno:nil dos:nil)
   fun {CalcularMovimientos Xs Ys}
		{System.show Xs}
		{System.show Ys}
		if Xs == nil then nil
		else
			case (Xs#Ys) of (H|Tx)#(H|Ty) then {CalcularMovimientos Tx Ty}
			[] (Hx|Tx)#(Hy|Ty) then
				Trenes = {PartirTren Xs Hy}
				Uno = {Lista.longitud Trenes.2} + 1
				Dos = {Lista.longitud Trenes.1}
				Xr = {Lista.agregar Trenes.2 Trenes.1}
			in
				uno(Uno) | dos(Dos) | uno(~Uno) | dos(~Dos) | {CalcularMovimientos Xr Ty}
			end
		end	 
   end
   
   
   % Devuelve la tupla que resulta de partir el tren Xs por el vagón Y. La tupla
   % resultante tiene la forma: <vagones previos a Y>#<vagones posteriores Y>.
   fun {PartirTren Xs Y}
%		case Xs of nil then nil
%		[] H|T then 
%			if H == Y then nil#T
%			else H|{PartirTren T Y}
%			end
%		end 
%   end
		Pos = { Lista . posicion Xs Y }
	in
		{ Lista.tomar Xs Pos -1}#{ Lista.eliminar Xs Pos }
	end


end
